namespace Xmef.Serializer
{
    using System;
    using Xmef.Library;
    using System.Text;
    using System.Collections.Generic;
    using System.Globalization;
    using Xmef.Interfaces;
    using Xmef.Serializer.Internal;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;

    [Serializable]
    public class XmlBinaryStringSerializer<T> : XmlStringSerializer<T>
    {
        protected override byte[] Deserialize(string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                try
                {
                    return ConvertFromBinaryString(data);
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorSync(ex);
                }
            }
            return null;
        }

        protected override string Serialize(byte[] data)
        {
            if (data != null)
            {
                try
                {
                    return ConvertToBinaryString(data);
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorSync(ex);
                }
            }
            return null;
        }

        private byte[] ConvertFromBinaryString(string data)
        {
            List<byte> result = new List<byte>();
            for (int i = 0; i < data.Length; i += 2)
            {
                result.Add(byte.Parse(string.Format(CultureInfo.InvariantCulture, "{0}{1}", data[i], data[i + 1]), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
            }
            return result.ToArray();
        }

        private string ConvertToBinaryString(byte[] data)
        {
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                result.Append(data[i].ToString("x2", CultureInfo.InvariantCulture));
            }
            return result.ToString();
        }

        protected override bool Serialize(T obj, Stream output, IXmlTypeFormatter formatter)
        {
            try
            {
                IXmlRuntimeSerializerInternal serializer = Runtime.GetSerializer<T>(formatter);
                if (serializer != null)
                {
                    BinaryFormatter binaryFormatter = new BinaryFormatter();
                    binaryFormatter.Serialize(output, obj);
                    return true;
                }
            }
            catch (ApplicationException ex)
            {
                LogHelper.WriteErrorSync(ex);
            }
            return false;
        }

        protected override bool Deserialize(Stream input, IXmlTypeFormatter formatter)
        {
            InitializeRuntimeObject(default(T));
            try
            {
                IXmlRuntimeSerializerInternal serializer = Runtime.GetSerializer<T>(formatter);
                if (serializer != null)
                {
                    BinaryFormatter binaryFormatter = new BinaryFormatter();
                    InitializeRuntimeObject((T)binaryFormatter.Deserialize(input));
                    return true;
                }
            }
            catch (ApplicationException ex)
            {
                LogHelper.WriteErrorSync(ex);
            }
            return false;
        }
    }
}